﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Dycox.Workflows.Events
{
    public abstract class ThreadLockProcessor : StageEventProcessor
    {
        public ThreadLockProcessor(string lockName)
        {
            if (string.IsNullOrWhiteSpace(lockName))
                throw new ArgumentNullException("lockName");

            _lockName = lockName;
        }

        private string _lockName;

        public string LockName
        {
            get { return _lockName; }
        }


        protected override void ProcessCore(WFStep step, EventScenario scenario)
        {

            WFThread thread = step.Thread;
            WFProcess process = thread.Process;

            PerformLockOperation(GetLock(step.Thread.Process), step);
        }

        internal ThreadLock GetLock(WFProcess process)
        {
            Workflow wf = WorkflowManager.GetWorkflow(process.WorkflowName);
            return wf.ThreadLocks.GetLock(_lockName);
        }

        protected abstract void PerformLockOperation(ThreadLock threadLock, WFThread thread);

        protected virtual void PerformLockOperation(ThreadLock threadLock, WFStep step)
        {
            PerformLockOperation(threadLock, step.Thread);
        }
    }

    public sealed class SetLockProcessor : ThreadLockProcessor
    {
        public SetLockProcessor(string lockName)
            : base(lockName)
        {

        }

        protected internal override bool IsScenarioSupported(Dycox.Workflows.EventScenario scenario)
        {
            return scenario == EventScenario.StepCreated;
        }

        protected override void PerformLockOperation(ThreadLock threadLock, WFThread thread)
        {
            threadLock.Set(thread);
        }
    }

    public sealed class ReleaseLockProcessor : ThreadLockProcessor
    {
        public ReleaseLockProcessor(string name)
            : base(name)
        {

        }

        protected override void PerformLockOperation(ThreadLock threadLock, WFThread thread)
        {
            threadLock.Release(thread.Process);
        }

        protected internal override bool IsScenarioSupported(EventScenario scenario)
        {
            return scenario == EventScenario.StepFinished;
        }
    }

    public sealed class WaitLockProcessor : ThreadLockProcessor
    {
        public WaitLockProcessor(string name)
            : base(name)
        {

        }

        protected override void PerformLockOperation(ThreadLock threadLock, WFThread thread)
        {
            throw new InvalidOperationException("This method should not been invoked.");
        }

        protected override void PerformLockOperation(ThreadLock threadLock, WFStep step)
        {
            WFThread thread = step.Thread;

            if (threadLock.Release(thread.Process) > 0)
            {
                threadLock.Workflow.Control.LockThread(step, threadLock);
            }
        }

        protected internal override bool IsScenarioSupported(EventScenario scenario)
        {
            return scenario == EventScenario.StepFinished;
        }

    }
}
